package ts.test.ch08.shizhan.shizhan2;

import ts.test.ch08.shizhan.shizhan1.LoggingInvocationHandler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;

public class ValidationProxy {
    public static Object  newInstance(Object target) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new ValidationInvocationHandler(target));
    }

    private static class ValidationInvocationHandler implements InvocationHandler {
        private final Object target;
        public ValidationInvocationHandler(Object target) {
            this.target = target;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Method[] methods = target.getClass().getInterfaces()[0].getMethods();
            for (Method m : methods) {
                if (m.getName().equals(method.getName()) && m.getParameterCount() == args.length){
                    Parameter[] parameters = m.getParameters();
                    for (int i = 0; i < parameters.length; i++) {
                        Validate validate = parameters[i].getAnnotation(Validate.class);
                        Object arg = args[i];
                        if (arg instanceof Double) {
                            Double value = (Double) arg;
                            if (validate.notEmpty() && value == null){
                                throw new ValidationException("Parameter cannot be null");
                            }
                            if (!Double.isInfinite(validate.minValue()) && value < validate.minValue()){
                                throw new ValidationException("Parameter value is too low" + value);
                            }
                            if (!Double.isInfinite(validate.maxValue()) && value > validate.maxValue()){
                                throw new ValidationException("Parameter value is too high" + value);
                            }
                        }else {
                            throw new ValidationException("Unsupported parameter type:" + arg.getClass().getName());
                        }
                    }
                }
            }
            return method.invoke(target, args);
        }
    }
}
